package com.cskaoyan.javase.oop1._16access._3why;

/**
 * 在某些应用场景下，需要在整个JVM全局保持某个类的对象唯一，这时候就需要单例模式来解决这个需求。
 *
 * 这个在整个JVM全局保持唯一的对象，就是单例。
 *
 * 单例模式普遍来说，有两种实现模式：
 *
 * 懒汉模式，指的是只有在确定要使用这个类对象时，才创建这个类对象。
 *
 * 由于是延迟创建对象，所以在需要用这个单例对象时，会略慢。
 *
 * 但程序的启动更快，因为不需要在启动时创建对象。
 *
 * 饿汉模式，无需确定是否使用这个类的对象，直接类加载时期就创建对象。
 *
 * 由于是直接类加载创建对象，所以在需要用这个单例对象时，会略快。
 *
 * 但程序的启动更快，因为需要在启动时创建对象。
 *
 * 接下来讲解一下具体实现。
 *
 * @since 17:17
 * @author wuguidong@cskaoyan.onaliyun.com
 */
public class Demo2 {
    public static void main(String[] args) {
        // new A();
        // System.out.println(A.aInstance);
        // A aInstance = A.getAInstance();
        // A aInstance2 = A.getAInstance();
        // A aInstance3 = A.getAInstance();


        B bInstance = B.getBInstance();
        B bInstance2 = B.getBInstance();
        B bInstance3 = B.getBInstance();
        B bInstance4 = B.getBInstance();
    }
}

// 希望A能够JVM全局唯一,单例对象,懒汉模式,只有在用到这个对象时,才创建
class A {
    // 既然是单例,外界必须不能随便创建对象,构造器需要私有化
    private A() {
    }

    // 现在外界不能创建对象了,只能在类的内部写一个方法,给外界提供对象,并且要保持这个对象唯一
    /*
        这个方法提供给外界使用,获取单例对象,所以访问权限修饰符应该是public
        然后这个类已经不能在外界创建对象了,这个方法肯定是静态方法(因为静态方法不需要创建对象即可访问)

        既然是获取对象的
        那么返回值类型就写A

        方法声明完毕后,考虑如何实现单例,怎么办呢?
        单例对象 必须全局唯一,考虑用一个静态成员变量创建自身类对象,那么这个对象就是唯一的(因为静态成员变量唯一)
     */
    private static A aInstance;

    public static A getAInstance() {
        // 调用这个方法时,判断该单例对象是否存在,存在就直接返回,否者就创建
        if (aInstance == null) {
            aInstance = new A();
            return aInstance;
        }
        // 说明对象已存在,直接返回
        return aInstance;
    }
}


// 饿汉模式
class B {
    private static B bInstance = new B();

    private B() {
    }

    public static B getBInstance() {
        return bInstance;
    }
}